#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include "libaxidma.h"

#include <pthread.h>
#include <semaphore.h>

#define AN706_SAMPLENUM (1920) //直接给个400M超大缓存 分成两块
#define AN706_REGBASE (0x43c00000)

//reg operate
int g_iAn706MemFileDev;
void *g_pAn706RegBase;

//axidma operate
axidma_dev_t g_AxiDmaDev;
array_t *g_apRxChannels;

void *g_pAn706DataBuf[2]; //双缓存

u_int8_t which_buff = 0;

bool g_waitFlag = true;
pthread_t thread[2];
sem_t recv_sem;

void adc_set_num(int num)
{

    *(volatile unsigned long *)(g_pAn706RegBase + 4) = num;
}

void adc_start()
{
     g_waitFlag = true;
    *(volatile unsigned long *)(g_pAn706RegBase) = 1;
}

void callbackAfterRecive(int channelid, void *data)
{
    (void)(data);
    (void)(channelid);
    // which_buff = 1 - which_buff;

    // printf("callbackAfterRecive \n");
    // for(int i=0;i<AN706_SAMPLENUM;i++){
    //     printf("%d \n", *((short*)data + i));
    // }
    // axidma_oneway_transfer(g_AxiDmaDev, g_apRxChannels->data[0], g_pAn706DataBuf[which_buff], AN706_SAMPLENUM * 2 * 8, false);

    // adc_set_num(AN706_SAMPLENUM + 2);
    // adc_start();
    // sem_post(&recv_sem);
    g_waitFlag = false;
}

int adc_int()
{
    //mmap the an706 reg base
    g_iAn706MemFileDev = open("/dev/mem", O_RDWR | O_SYNC);
    if (g_iAn706MemFileDev < 0)
    {
        printf("ERROR: can not open /dev/mem\n");
        return 0;
    }
    g_pAn706RegBase = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, g_iAn706MemFileDev, AN706_REGBASE);
    if (!g_pAn706RegBase)
    {
        printf("ERROR: unable to mmap adc registers\n");

        //close an706 memory file dev
        if (g_iAn706MemFileDev)
            close(g_iAn706MemFileDev);

        return 0;
    }
    return 1;
}

void *adc_thread()
{
    printf("adc_thread : start\n");
    while (1)
    {
        // sem_wait(&recv_sem);
        sleep(1);
        printf("adc recv callback\n");
    }
    printf("adc_thread : stop\n");
    pthread_exit(NULL);
}

void init_thread()
{

    int temp;
    sem_init(&recv_sem, 0, 0);

    memset(&thread, 0, sizeof(thread)); //comment1
    //创建线程
    if ((temp = pthread_create(&thread[0], NULL, adc_thread, NULL)) != 0) //comment2
        printf("ADC线程创建失败!\n");
}

int main()
{
    //init axidma device
    g_AxiDmaDev = axidma_init();
    if (g_AxiDmaDev == NULL)
    {
        printf("Error: can not initialize the AXI DMA device\n");
        return 0;
    }

    //get avaliable rx channels
    g_apRxChannels = (array_t *)axidma_get_dma_rx(g_AxiDmaDev);
    if (g_apRxChannels->len < 1)
    {
        printf("Error: no receive channels found\n");
        return 0;
    }

    //print avaliable channels
    for (int i = 0; i < g_apRxChannels->len; i++)
    {
        printf("INFO: receive channel ID: %d\n", g_apRxChannels->data[i]);
    }

    // init_thread();

    //start DMA recive
    //per channel data num = 1920 ,per data 16bit,total has 8 adc channel data
    g_pAn706DataBuf[0] = axidma_malloc(g_AxiDmaDev, AN706_SAMPLENUM * 2 * 8);
    g_pAn706DataBuf[1] = axidma_malloc(g_AxiDmaDev, AN706_SAMPLENUM * 2 * 8);
    // printf("the init dma recive buf:\n");

    printf("preper to start adc\n");
    axidma_stop_transfer(g_AxiDmaDev, g_apRxChannels->data[0]);
    axidma_set_callback(g_AxiDmaDev, g_apRxChannels->data[0], callbackAfterRecive, NULL);
    axidma_oneway_transfer(g_AxiDmaDev, g_apRxChannels->data[0], g_pAn706DataBuf[0], AN706_SAMPLENUM * 2 * 8, false);

    // adc_set_num(AN706_SAMPLENUM + 2);
    // adc_start();

    printf("the ADC has start...\n");

    //等待线程结束
    if (thread[0] != 0)
    {
        pthread_join(thread[0], NULL);
        printf("process thread descroy\n");
    }

    sem_destroy(&recv_sem);

    //close an706 memory file dev
    if (g_iAn706MemFileDev)
        close(g_iAn706MemFileDev);

    //munmap
    munmap(g_pAn706RegBase, MAP_SHARED);

    axidma_destroy(g_AxiDmaDev);

    return 0;
}
